package com.dycong.common.Lamda;

import org.junit.Test;

import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

import static org.junit.Assert.*;

/**
 * @author dycong
 * @date 2018/4/20 14:32
 */
public class TestCompletableFuture {


    /**
     * CompletableFuture的方法如果以Async结尾，它会异步的执行(没有指定executor的情况下)， 异步执行通过ForkJoinPool实现，
     * 它使用守护线程去执行任务。注意这是CompletableFuture的特性， 其它CompletionStage可以override这个默认的行为。
     *
     * @throws InterruptedException
     */
    @Test
    public void runAsyncExample() throws InterruptedException {
        CompletableFuture cf = CompletableFuture.runAsync(() -> {
            assertTrue(Thread.currentThread().isDaemon());
            System.out.println("go to sleep");
            randomSleep();

        });
        assertFalse(cf.isDone());
        sleepEnough();
        while (!cf.isDone()) {

        }
        System.out.println(cf.getNow(null));
    }

    @Test
    public void supplyAsyncExample() throws InterruptedException {
        String ret = "ok";
        CompletableFuture cf = CompletableFuture.supplyAsync(() -> {
            assertTrue(Thread.currentThread().isDaemon());
            System.out.println("go to sleep");
            randomSleep();

            return ret;
        });
        assertFalse(cf.isDone());
        sleepEnough();
        while (!cf.isDone()) {

        }
        System.out.println(cf.getNow(null));
    }


    /**
     * <U> CompletableFuture<U> completedFuture(U value)
     */
    @Test
    public void thenApplyExample() {
        CompletableFuture<String> cf = CompletableFuture.completedFuture("message").thenApply(s -> {
            System.out.println(Thread.currentThread().isDaemon());
            return s.toUpperCase();
        });
        assertEquals("MESSAGE", cf.getNow(null));
    }

    /**
     * 通过调用异步方法(方法后边加Async后缀)，串联起来的CompletableFuture可以异步地执行（使用ForkJoinPool.commonPool()）
     */
    @Test
    public void thenApplyAsyncExample() {
        CompletableFuture<String> cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
            System.out.println(Thread.currentThread().isDaemon());
            randomSleep();
            return s.toUpperCase();
        });
        while (!cf.isDone()) {
        }
        assertEquals("MESSAGE", cf.getNow(null));
    }

    /**
     * 异步方法一个非常有用的特性就是能够提供一个Executor来异步地执行CompletableFuture。这个例子演示了如何使用一个固定大小的线程池来应用大写函数。
     */
    @Test
    public void thenApplyAsyncWithExecutorExample() {
        CompletableFuture<String> cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
            System.out.println(Thread.currentThread());
            randomSleep();
            return s.toUpperCase();
        }, executor);
        while (!cf.isDone()) {
        }
        assertEquals("MESSAGE", cf.getNow(null));
    }

    /**
     * 如果下一阶段接收了当前阶段的结果，但是在计算的时候不需要返回值(它的返回类型是void)， 那么它可以不应用一个函数，而是一个消费者， 调用方法也变成了thenAccept:
     */
    @Test
    public void thenAcceptExample() {
        StringBuilder result = new StringBuilder();
        CompletableFuture.completedFuture("thenAccept message").thenAccept(System.out::println)
                .thenAccept(s -> result.append(s));
        assertTrue("Result was empty", result.length() > 0);
    }


    static ExecutorService executor = Executors.newFixedThreadPool(3, new ThreadFactory() {
        int count = 1;

        @Override
        public Thread newThread(Runnable runnable) {
            return new Thread(runnable, "custom-executor-" + count++);
        }
    });

    private void randomSleep() {
        Random random = new Random();
        try {
            Thread.sleep(random.nextInt(20000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void sleepEnough() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sleep enough");
    }
}
